﻿#include "strategy.h"
#include <QDebug>
#include <QMap>
#include <functional>
Strategy::Strategy(Player *player, Cards &cards)
{
    m_player=player;
    m_cards=cards;
}
Cards Strategy::makeStrategy()
{
    //得到出牌玩家和打出的牌

    Player* player=m_player->getPendPlayer();
    Cards pendCards=m_player->getPendCards();

    //判断上次出牌玩家是不是我自己
    if(player==m_player||player==nullptr)
    {
        //如果是我自己，出牌没有限制
       Cards cards=firstPlay();
       qDebug()<<"出牌量："<<QString::number(cards.cardcount());
       return cards;
    }
    else
    {
        //如果不是我自己需要找比出牌玩家大的牌
        PlayHand type(pendCards);
        //找到比当前玩家大的牌
        Cards cards= getGreaterCards(type);
        //判断要不要出找到的牌
        bool shouldBeat= whetherToBeat(cards);

        if(shouldBeat)
        {
            return cards;
        }
        else
        {
            //返回空的
            return Cards();
        }
    }
    return Cards();

}

Cards Strategy::firstPlay()
{
        PlayHand hand(m_cards);
        if(hand.getHandType() != PlayHand::Hand_Unknown)
        {
            return m_cards;
        }
        // 不是单一牌型
        // 判断玩家手中是否有顺子
        QVector<Cards> optimalSeq = pickOptimalSeqSingles();
        if(!optimalSeq.isEmpty())
        {
            // 得到单牌的数量
            int baseNum = findCardsByCount(1).size();
            // 把得到的顺子的集合从玩家手中删除
            Cards save = m_cards;
            save.remove(optimalSeq);
            int lastNum = Strategy(m_player, save).findCardsByCount(1).size();
            if(baseNum > lastNum)
            {
                return optimalSeq[0];
            }
        }

        bool hasPlane, hasTriple, hasPair;
        hasPair = hasTriple = hasPlane = false;
        Cards backup = m_cards;

        // 有没有炸弹
        QVector<Cards> bombArray = findCardType(PlayHand(PlayHand::Hand_Bomb, Card::Card_Begin, 0), false);
        backup.remove(bombArray);

        // 有没有飞机
        QVector<Cards> planeArray = Strategy(m_player, backup).findCardType(PlayHand(PlayHand::Hand_Plane, Card::Card_Begin, 0), false);
        if(!planeArray.isEmpty())
        {
            hasPlane = true;
            backup.remove(planeArray);
        }

        // 有没有三张点数相同的牌
        QVector<Cards> seqTripleArray = Strategy(m_player, backup).findCardType(PlayHand(PlayHand::Hand_Triple, Card::Card_Begin, 0), false);
        if(!seqTripleArray.isEmpty())
        {
            hasTriple = true;
            backup.remove(seqTripleArray);
        }

        // 有没有连对
        QVector<Cards> seqPairArray = Strategy(m_player, backup).findCardType(PlayHand(PlayHand::Hand_Seq_Pair, Card::Card_Begin, 0), false);
        if(!seqPairArray.isEmpty())
        {
            hasPair = true;
            backup.remove(seqPairArray);
        }

        if(hasPair)
        {
            Cards maxPair;
            for(int i=0; i<seqPairArray.size(); ++i)
            {
                if(seqPairArray[i].cardcount() > maxPair.cardcount())
                {
                    maxPair = seqPairArray[i];
                }
            }
            return maxPair;
        }

        if(hasPlane)
        {
            // 1. 飞机带两个对儿
            bool twoPairFond = false;
            QVector<Cards> pairArray;
            for(Card::CardPoint point = Card::Card_3; point <= Card::Card_10; point = Card::CardPoint(point + 1))
            {
                Cards pair = Strategy(m_player, backup).findSamePointCards(point, 2);
                if(!pair.isEmpty())
                {
                    pairArray.push_back(pair);
                    if(pairArray.size() == 2)
                    {
                        twoPairFond = true;
                        break;
                    }
                }
            }
            if(twoPairFond)
            {
                Cards tmp = planeArray[0];
                tmp.add(pairArray);
                return tmp;
            }
            // 2. 飞机带两个单牌
            else
            {
                bool twoSingleFond = false;
                QVector<Cards> singleArray;
                for(Card::CardPoint point = Card::Card_3; point <= Card::Card_10; point = Card::CardPoint(point + 1))
                {
                    if(backup.pointCount(point) == 1)
                    {
                        Cards single = Strategy(m_player, backup).findSamePointCards(point, 1);
                        if(!single.isEmpty())
                        {
                            singleArray.push_back(single);
                            if(singleArray.size() == 2)
                            {
                                twoSingleFond = true;
                                break;
                            }
                        }
                    }
                }
                if(twoSingleFond)
                {
                    Cards tmp = planeArray[0];
                    tmp.add(singleArray);
                    return tmp;
                }
                else
                {
                    // 3. 飞机
                    return planeArray[0];
                }
            }
        }

        if(hasTriple)
        {
            if(PlayHand(seqTripleArray[0]).getCardPoint() < Card::Card_A)
            {
                for(Card::CardPoint point = Card::Card_3; point <= Card::Card_A; point = Card::CardPoint(point+1))
                {
                    int pointCount = backup.pointCount(point);
                    if(pointCount == 1)
                    {
                        Cards single = Strategy(m_player, backup).findSamePointCards(point, 1);
                        Cards tmp = seqTripleArray[0];
                        tmp.add(single);
                        return tmp;
                    }
                    else if(pointCount == 2)
                    {
                        Cards pair = Strategy(m_player, backup).findSamePointCards(point, 2);
                        Cards tmp = seqTripleArray[0];
                        tmp.add(pair);
                        return tmp;
                    }
                }
            }
            // 不带副牌
            return seqTripleArray[0];
        }
        // 单牌或者对儿牌
        Player* nextPlayer = m_player->getNextPlayer();
        if(nextPlayer->getCards().cardcount() == 1 && m_player->getRole() != nextPlayer->getRole())
        {
            for(Card::CardPoint point = Card::CardPoint(Card::Card_End-1);
                point >= Card::Card_3; point = Card::CardPoint(point-1))
            {
                int pointCount = backup.pointCount(point);
                if(pointCount == 1)
                {
                    Cards single = Strategy(m_player, backup).findSamePointCards(point, 1);
                    return single;
                }
                else if(pointCount == 2)
                {
                    Cards pair = Strategy(m_player, backup).findSamePointCards(point, 2);
                    return pair;
                }
            }
        }
        else
        {
            for(Card::CardPoint point =  Card::Card_3;
                point < Card::Card_End; point = Card::CardPoint(point+1))
            {
                int pointCount = backup.pointCount(point);
                if(pointCount == 1)
                {
                    Cards single = Strategy(m_player, backup).findSamePointCards(point, 1);
                    return single;
                }
                else if(pointCount == 2)
                {
                    Cards pair = Strategy(m_player, backup).findSamePointCards(point, 2);
                    return pair;
                }
            }
        }
        if(m_player->getRole()==Player::lord&&m_cards.cardcount()==20)
        {
            Cards cards;
            qDebug()<<"cards数量："<<QString::number(cards.cardcount());
            cards.add(m_cards.toCardList()[0]);
            return cards;
        }
        qDebug()<<"地主没出牌";
        return Cards();
}

Cards Strategy::getGreaterCards(PlayHand hand)
{
    //1.出牌玩家和当前玩家是不是一伙的
    Player* pendPlayer=m_player->getPendPlayer();
    //不是一伙的并且出牌玩家手牌少要获胜了，必须阻止他
    if(pendPlayer!=nullptr&& pendPlayer->getRole()!=m_player->getRole()&&pendPlayer->getCards().cardcount()<=3)//bug
    {
        //找找炸弹牌
        QVector<Cards> bombs=findCardsByCount(4);
        for(int i=0;i<bombs.size();i++)
        {
            if(PlayHand(bombs[i]).canBeat(hand))
            {

                return bombs[i];
            }
        }
        //找王炸
        Cards sj=findSamePointCards(Card::Card_SJ,1);
        Cards bj=findSamePointCards(Card::Card_BJ,1);
        if(!sj.isEmpty()&&!bj.isEmpty())
        {
            Cards temp;
            temp<<sj<<bj;

            return temp;
        }
    }
    //2.当前玩家和下一个玩家是不是一伙的
    Player* nextPlayer=m_player->getNextPlayer();
    //先看看把顺子剔除后能不能压制当前牌
    Cards remain=m_cards;
    //remain.remove(顺子);

    QVector<Cards> beatCardsArray=Strategy(m_player,remain).findCardType(hand,true);
    //剔除顺子后看有没有牌可以压制
    if(!beatCardsArray.isEmpty())
    {
        if(m_player->getRole()!=nextPlayer->getRole()&&nextPlayer->getCards().cardcount()<=2)
        {
            return beatCardsArray.back();
        }
        else
        {
            return beatCardsArray.front();
        }
    }
    else
    {
        //剔除顺子没有牌压制，把牌复原
        QVector<Cards> beatCardsArray=Strategy(m_player,m_cards).findCardType(hand,true);
        //剔除顺子后看有没有牌可以压制
        if(!beatCardsArray.isEmpty())
        {
            if(m_player->getRole()!=nextPlayer->getRole()&&nextPlayer->getCards().cardcount()<=2)
            {
                return beatCardsArray.back();
            }
            else
            {
                return beatCardsArray.front();
            }
        }
    }

    return Cards();
}

bool Strategy::whetherToBeat(Cards cards)
{
    if(cards.isEmpty())
    {
        return false;
    }
    //判断出牌玩家与是不是一伙的
    Player* player=m_player->getPendPlayer();
    if(m_player->getRole()==player->getRole())//如果是一伙的
    {
        //手里的牌所剩无几，并且是一个完整的牌型
        Cards remainCards=m_cards;
        remainCards.remove(cards);
        PlayHand hand(remainCards);
        if(hand.getHandType()!=PlayHand::Hand_Unknown)
        {
            return true;
        }
        //如果将要打出的牌cards最小的牌是2，或者大小王。不能出牌打队友
       Card::CardPoint point= PlayHand(cards).getCardPoint();
       if(point==Card::Card_2||point==Card::Card_SJ||point==Card::Card_BJ)
       {
           return false;
       }
    }
    else
    {
        PlayHand myHand(cards);
        //如果要出的牌是3带1或者3带2，并且是三个2，则不出
        if((myHand.getHandType()==PlayHand::Hand_Triple_Single||myHand.getHandType()==PlayHand::Hand_Triple_Pair)&&myHand.getCardPoint()==Card::Card_2)
        {
            return false;
        }
        if(myHand.getHandType()==PlayHand::Hand_Pair&&myHand.getCardPoint()==Card::Card_2&&player->getCards().cardcount()>=10&&m_player->getCards().cardcount()>=5)
        {
            return false;
        }
    }
    return true;
}


Cards Strategy::findSamePointCards(Card::CardPoint point, int count)
{
    //大小王
    if(count<1||count>4)
    {
        return Cards();
    }
    if(point==Card::Card_SJ||point==Card::Card_BJ)
    {
        if(count>1)
        {
            return Cards();
        }
        Card card;
        card.setPoint(point);
        card.setSuit(Card::Suit_Begin);
        if(m_cards.contains(card))
        {
            Cards cards;
            cards.add(card);
            return cards;
        }
        return Cards();
    }
    //不是大小王
    int findCount=0;
    Cards findCards;
    for(int suit=Card::Suit_Begin+1;suit<Card::Suit_End;suit++)
    {
        Card card;
        card.setPoint(point);
        card.setSuit((Card::CardSuit)suit);
        if(m_cards.contains(card))
        {
            findCount++;
            findCards.add(card);
            if(findCount==count)
            {
                return findCards;
            }
        }
    }
    return Cards();
}

QVector<Cards> Strategy::findCardsByCount(int count)
{
    if(count<1||count>4)
    {
        return QVector<Cards>();
    }
    QVector<Cards> cardsArray;
    for(Card::CardPoint point=Card::Card_3;point<Card::Card_End;point=(Card::CardPoint)(point+1))
    {
        if(m_cards.pointCount(point)==count)
        {
            Cards cards;
            cards<<findSamePointCards(point,count);
            cardsArray<<cards;
        }
    }
    return cardsArray;
}

Cards Strategy::getRangeCards(Card::CardPoint begin, Card::CardPoint end)
{
    Cards rangeCards;
    for(Card::CardPoint point=begin;point<end;point=(Card::CardPoint)(point+1))
    {
        int count=m_cards.pointCount(point);
        Cards cards=findSamePointCards(point,count);
        rangeCards<<cards;
    }
    return rangeCards;
}

QVector<Cards> Strategy::findCardType(PlayHand hand, bool beat)
{
    PlayHand::HandType type=hand.getHandType();
    Card::CardPoint point=hand.getCardPoint();
    int extra=hand.getExtra();

    //确定起始点数
    Card::CardPoint beginPoint=beat?Card::CardPoint(point+1):Card::Card_3;
    switch(type)
    {
    case PlayHand::Hand_Single:
        return getCards(beginPoint,1);
    case PlayHand::Hand_Pair:
        return getCards(beginPoint,2);
    case PlayHand::Hand_Triple:
        return getCards(beginPoint,3);
    case PlayHand::Hand_Triple_Single:
        return getTripleSingleOrPair(beginPoint,PlayHand::Hand_Single);
    case PlayHand::Hand_Triple_Pair:
        return getTripleSingleOrPair(beginPoint,PlayHand::Hand_Pair);
    case PlayHand::Hand_Plane:
        return getPlane(beginPoint);
    case PlayHand::Hand_Plane_Two_Single:
        return getPlane2SingleOr2Pair(beginPoint,PlayHand::Hand_Single);
    case PlayHand::Hand_Plane_Two_Pair:
        return getPlane2SingleOr2Pair(beginPoint,PlayHand::Hand_Pair);
    case PlayHand::Hand_Seq_Pair:
    {
        struct CardInfo info;
        info.base=3;
        info.beat=beat;
        info.begin=beginPoint;
        info.end=Card::Card_Q;
        info.extra=extra;
        info.getSeq=&Strategy::getBaseSeqPair;
        info.number=2;
        return getSepPairOrSingle(info);
    }
    case PlayHand::Hand_Seq_Single:
    {
        struct CardInfo info;
        info.base=5;
        info.beat=beat;
        info.begin=beginPoint;
        info.end=Card::Card_10;
        info.extra=extra;
        info.getSeq=&Strategy::getBaseSeqSingle;
        info.number=1;
        return getSepPairOrSingle(info);
    }
    case PlayHand::Hand_Bomb:
       return getBomb(beginPoint);
    default:
        return QVector<Cards>();

    }


}

QVector<Cards> Strategy::getCards(Card::CardPoint point, int number)
{
    QVector<Cards> findCardsArray;
    for(Card::CardPoint pt=point;pt<Card::Card_End;pt=(Card::CardPoint)(pt+1))
    {
       //如果牌恰好等于number才算，避免破坏拆解了炸弹等
        if(m_cards.pointCount(pt)==number)
        {
            Cards cs=findSamePointCards(pt,number);
            if(!cs.isEmpty())
            {
                findCardsArray.push_back(cs);
            }
        }
    }
    return findCardsArray;
}

QVector<Cards> Strategy::getTripleSingleOrPair(Card::CardPoint point, PlayHand::HandType type)
{
    //找到点数相同的三张牌
    QVector<Cards> findCardArray=getCards(point,3);
    if(!findCardArray.isEmpty())
    {
        Cards remainCards=m_cards;
        remainCards.remove(findCardArray);//剔除所有的三张牌
        //寻找单牌或者成对的牌---重新创建一个strategy对象，将剩余的牌初始化进该对象。
        Strategy st(m_player,remainCards);
        QVector<Cards> cardsArray=st.findCardType(PlayHand(type,Card::Card_Begin,0),false);
        if(!cardsArray.isEmpty())
        {
            for(int i=0;i<findCardArray.size();i++)
            {
                findCardArray[i].add(cardsArray[0]);
            }
        }
        else
        {
            //找不到的话把找到的3张牌清除
            findCardArray.clear();
        }
    }
    //将三张牌从用户手牌去除
    //搜索单牌或对牌
    //将找到的三张牌与单牌对牌组合成数组
    //返回数组
    return findCardArray;
}

QVector<Cards> Strategy::getPlane(Card::CardPoint point)
{
    QVector<Cards> findCardArray;
    for(Card::CardPoint pt=point;pt<Card::Card_K;pt=(Card::CardPoint)(pt+1))
    {
       Cards prevCards= findSamePointCards(pt,3);
       Cards nextCards=findSamePointCards((Card::CardPoint)(pt+1),3);
       if(!prevCards.isEmpty()&&!nextCards.isEmpty())
       {
           Cards cards;
           cards<<prevCards<<nextCards;
           findCardArray.push_back(cards);
       }
    }
    return findCardArray;
}

QVector<Cards> Strategy::getPlane2SingleOr2Pair(Card::CardPoint point, PlayHand::HandType type)
{
    QVector<Cards> findCardArray=getPlane(point);
    QVector<Cards> returnArray;
    if(!findCardArray.isEmpty())
    {
        //剔除飞机牌
        Cards remainCards=m_cards;
        remainCards.remove(findCardArray);
        Strategy st(m_player,remainCards);
        QVector<Cards> cards=st.findCardType(PlayHand(type,point,0),false);
        if(cards.size()>1)
        {
            for(int i=0;i<findCardArray.size();i++)
            {
                Cards temp;
                temp<<findCardArray[i]<<cards[0]<<cards[1];
                returnArray<<temp;
            }
        }
    }
    return returnArray;
}

QVector<Cards> Strategy::getSepPairOrSingle(CardInfo &info)
{
    QVector<Cards> findCardsArray;
    if(info.beat)//beat为true要求对牌型的点数和数量都有要求
    {
        //找压过牌型的牌
        for(Card::CardPoint pt=info.begin;pt<=info.end;pt=(Card::CardPoint)(pt+1))
        {
            bool found=true;
            Cards seqCards;
            for(int i=0;i<info.extra;i++)
            {
                Cards cards=findSamePointCards((Card::CardPoint)(pt+i),info.number);
                if(cards.isEmpty()||(pt+info.extra>=Card::Card_2))
                {
                    found=false;
                    seqCards.clear();
                    break;
                }
                else
                {
                    seqCards<<cards;
                }
            }
            if(found)
            {
                findCardsArray<<seqCards;
                return findCardsArray;
            }
        }
    }
    else//对点数和数量不做要求，找出所有符合牌型的牌
    {
        //先把连对要求的三对牌找出来
        for(Card::CardPoint pt=info.begin;pt<=info.end;pt=(Card::CardPoint)(pt+1))
        {
            Cards baseSeq=(this->*info.getSeq)(pt);
            if(baseSeq.isEmpty())
            {
                continue;
            }
            findCardsArray<<baseSeq;
            int followed=info.base;//已经连对的对数
            Cards alreadyFollowedCards;//存储后续找到的对牌
            while(true)
            {
                Card::CardPoint followedPoint = Card::CardPoint(pt + followed);
                if(followedPoint>=Card::Card_2)
                {
                    break;
                }
                Cards cards=findSamePointCards(followedPoint,info.number);
                if(!cards.isEmpty())
                {
                    alreadyFollowedCards<<cards;
                    Cards temp=baseSeq;
                    temp<<alreadyFollowedCards;
                    findCardsArray<<temp;
                    followed++;
                }
                else
                {
                    break;
                }
            }
        }
    }
    return findCardsArray;
}

Cards Strategy::getBaseSeqPair(Card::CardPoint pt)
{
    Cards cards0=findSamePointCards(pt,2);
    Cards cards1=findSamePointCards((Card::CardPoint)(pt+1),2);
    Cards cards2=findSamePointCards((Card::CardPoint)(pt+2),2);
    Cards baseSeq;
    if(!cards0.isEmpty()&&!cards1.isEmpty()&&!cards2.isEmpty())
    {
        baseSeq<<cards0<<cards1<<cards2;
    }
    return baseSeq;
}

Cards Strategy::getBaseSeqSingle(Card::CardPoint pt)
{
    Cards cards0=findSamePointCards(pt,1);
    Cards cards1=findSamePointCards((Card::CardPoint)(pt+1),1);
    Cards cards2=findSamePointCards((Card::CardPoint)(pt+2),1);
    Cards cards3=findSamePointCards((Card::CardPoint)(pt+3),1);
    Cards cards4=findSamePointCards((Card::CardPoint)(pt+4),1);
    Cards baseSeq;
    if(!cards0.isEmpty()&&!cards1.isEmpty()&&!cards2.isEmpty()&&!cards3.isEmpty()&&!cards4.isEmpty())
    {
        baseSeq<<cards0<<cards1<<cards2<<cards3<<cards4;
    }
    return baseSeq;
}

QVector<Cards> Strategy::getBomb(Card::CardPoint point)
{
    QVector<Cards> findCardsArry;
    for(Card::CardPoint pt=point;pt<Card::Card_End;pt=(Card::CardPoint)(pt+1))
    {
        Cards cards= findSamePointCards(pt,4);
        if(!cards.isEmpty())
        {
            findCardsArry<<cards;
        }
    }
    return findCardsArry;
}

void Strategy::pickSeqSingles(QVector<QVector<Cards>>& allSeqRecord,QVector<Cards> &seqSingle, Cards &cards)
{
    //1.得到所有顺子的组合
    QVector<Cards> allSeq= Strategy(m_player,cards).findCardType(PlayHand(PlayHand::Hand_Seq_Single,Card::Card_Begin,0),false);
    if(allSeq.isEmpty())
    {
        allSeqRecord<<seqSingle;
    }
    else
    {
        Cards saveCards=cards;
        for(int i=0;i<allSeq.size();i++)
        {
            Cards aScheme=allSeq.at(i);
            Cards temp=saveCards;
            temp.remove(aScheme);
            QVector<Cards> seqArray=seqSingle;
            seqArray<<aScheme;
            pickSeqSingles(allSeqRecord,seqArray,temp);
        }
    }
    //2.对顺子进行筛选
}

QVector<Cards> Strategy::pickOptimalSeqSingles()
{
    QVector<QVector<Cards>> SeqRecord;
    QVector<Cards> seqSingles;
    Cards save=m_cards;
    save.remove(findCardsByCount(4));
    save.remove(findCardsByCount(3));
    pickSeqSingles(SeqRecord,seqSingles,save);
    if(SeqRecord.isEmpty())
    {
        return QVector<Cards>();
    }
    QMap<int,int> seqMarks;
        for(int i=0; i<SeqRecord.size(); ++i)
        {
            Cards backupCards = m_cards;
            QVector<Cards> seqArray = SeqRecord[i];
            backupCards.remove(seqArray);

            // 判断剩下的单牌是数量, 数量越少,顺子的组合就越合理
            QVector<Cards> singleArray = Strategy(m_player, backupCards).findCardsByCount(1);

            QVector<Card> cardList;
            for(int j=0; j<singleArray.size(); ++j)
            {
                cardList << singleArray[j].toCardList();
            }
            // 找点数相对较大一点顺子
            int mark = 0;
            for(int j=0; j<cardList.size(); ++j)
            {
                mark += cardList[j].point() + 15;
            }
            seqMarks.insert(i, mark);
        }

        // 遍历map
        int value = 0;
        int comMark = 1000;
        auto it = seqMarks.constBegin();
        for(;it!=seqMarks.constEnd(); ++it)
        {
            if(it.value() < comMark)
            {
                comMark = it.value();
                value = it.key();
            }
        }

        return SeqRecord[value];
}
